﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Runtime.InteropServices;

namespace LidarCalibrateAndButtonImitateTool
{
    public partial class MainForm : Form
    {
        [DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
        public static extern void keybd_event(Keys bVk, // 第一个为按键的虚拟键值，可以使用枚举值System.Windows.Forms.Keys
            byte bScan, // 第二个参数为扫描码，一般不用设置，用0代替就行
            uint dwFlags, // 第三个参数为选项标志，如果为keydown则置"0"，如果为keyup则设成"2"
            uint dwExtraInfo // 第四个参数一般也是置0即可
        );

        // 全局变量定义
        LidarConfig g_lidar1Config, g_lidar2Config;

        public MainForm()
        {
            InitializeComponent();

            // 初始化变量


            // 初始化UI


            // 初始化定时器
            timerValidateSerialPort.Interval = 1000;
            timerValidateSerialPort.Start();
            timerKeyRelease.Start();

            // 初始化串口及事件
            g_serialPort1.BaudRate = 115200;
            g_serialPort2.BaudRate = 115200;
            g_serialPort1.DtrEnable = true;
            g_serialPort2.DtrEnable = true;
            g_serialPort1.DataReceived += G_serialPort1_DataReceived;
            g_serialPort2.DataReceived += G_serialPort2_DataReceived;

            // 加载虚拟按键配置信息
            LoadConfig(0);
            LoadConfig(1);
        }

        // 加载虚拟按键配置信息
        private void LoadConfig(int lidarChannel)
        {
            // 解析输入数据
            try
            {
                if (lidarChannel == 0) // Lidar1
                {
                    string json = File.ReadAllText("Lidar1_config.json"); // 导入Lidar1的配置数据，json格式
                    LidarConfig lidar1Config = JsonConvert.DeserializeObject<LidarConfig>(json); // 把配置数据反序列化成对象
                    g_lidar1Config = new LidarConfig();
                    g_lidar1Config = lidar1Config;

                    cboxLidar1BtnImitateKey.SelectedIndex = 0;
                    TreeNode treeNode = new TreeNode(lidar1Config.lidarName, 2, 2); // 第1个2代表图标ID，第2个2代表点击时图标展示和我们图标ID对应
                    tviewLidar1.Nodes.Clear(); // 删除所有节点
                    tviewLidar1.Nodes.Add(treeNode); // 添加根节点
                    tviewLidar1.Select();
                    foreach (BtnConfig config in lidar1Config.btnsConfig) // 遍历json
                    {
                        TreeNode childNode = new TreeNode(config.buttonName, 2, 2);
                        tviewLidar1.SelectedNode.Nodes.Add(childNode); // 选中根节点，添加子节点
                        tviewLidar1.SelectedNode.Expand();
                    }
                }
                else if (lidarChannel == 1) // Lidar2
                {
                    string json = File.ReadAllText("Lidar2_config.json"); // 导入Lidar1的配置数据，json格式
                    LidarConfig lidar2Config = JsonConvert.DeserializeObject<LidarConfig>(json); // 把配置数据反序列化成对象
                    g_lidar2Config = new LidarConfig();
                    g_lidar2Config = lidar2Config;

                    cboxLidar2BtnImitateKey.SelectedIndex = 0;
                    TreeNode treeNode = new TreeNode(lidar2Config.lidarName, 2, 2); // 第1个2代表图标ID，第2个2代表点击时图标展示和我们图标ID对应
                    tviewLidar2.Nodes.Clear(); // 删除所有节点
                    tviewLidar2.Nodes.Add(treeNode); // 添加根节点
                    tviewLidar2.Select();
                    foreach (BtnConfig config in lidar2Config.btnsConfig) // 遍历json
                    {
                        TreeNode childNode = new TreeNode(config.buttonName, 2, 2);
                        tviewLidar2.SelectedNode.Nodes.Add(childNode); // 选中根节点，添加子节点
                        tviewLidar2.SelectedNode.Expand();
                    }
                }

                Console.WriteLine("Lidar config loaded!");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Please input correct data!");
                MessageBox.Show(ex.Message, "Error");
            }
        }

        //更新UI代理       
        delegate void DelegateUiUpdate(string data);
        private void TxtLidar1DebugUpdate(string data)
        {
            txtLidar1Debug.AppendText(data + "\r\n");
        }
        private void TxtLidar2DebugUpdate(string data)
        {
            txtLidar2Debug.AppendText(data + "\r\n");
        }

        private void G_serialPort2_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                string data = g_serialPort2.ReadLine();
                Console.WriteLine(data);

                // 输出到UI
                object[] args = { data };
                this.Invoke(new DelegateUiUpdate(TxtLidar2DebugUpdate), args);

                // 解析数据
                if (data.Split(',').Length == 2)
                {
                    ProcessLidar2Data(data);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Lidar 2 receive data error!");
            }
        }

        // 接收激光雷达1串口过来的数据
        private void G_serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try 
            {
                string data = g_serialPort1.ReadLine();
                Console.WriteLine(data);

                // 输出到UI
                object[] args = { data };
                this.Invoke(new DelegateUiUpdate(TxtLidar1DebugUpdate), args);

                // 解析数据
                if (data.Split(',').Length == 2)
                {
                    ProcessLidar1Data(data);
                }
            }
            catch (Exception)
            {
                Console.WriteLine("Lidar 1 receive data error!");
            }
        }

        /// <summary>
        /// 处理激光雷达1的数据
        /// </summary>
        /// <param name="data">激光雷达数据</param>
        /// <param name="portNum">激光雷达串口号</param>
        private void ProcessLidar1Data(string data)
        {
            data = data.Replace("\r", "").Replace("\n", "");
            string[] cordinates = data.Split(',');
            try
            {
                for (int i = 0; i < g_lidar1Config.btnsConfig.Length; i++)
                {
                    if (InRange(g_lidar1Config.btnsConfig[i].virtualKeyConfig.XCenter,
                    g_lidar1Config.btnsConfig[i].virtualKeyConfig.YCenter,
                    g_lidar1Config.btnsConfig[i].virtualKeyConfig.XRange,
                    g_lidar1Config.btnsConfig[i].virtualKeyConfig.YRange,
                    int.Parse(cordinates[0]),
                    int.Parse(cordinates[1])))
                    {
                        // 确认触发冷却
                        DateTime dTimeEnd = DateTime.Now;
                        TimeSpan timeSpan = dTimeEnd - g_lidar1Config.btnsConfig[i].virtualKeyConfig.LastTriggerTime;
                        g_lidar1Config.btnsConfig[i].virtualKeyConfig.LastTriggerTime = dTimeEnd; // 更新按键最后触发时间
                        //if (timeSpan != TimeSpan.Zero && timeSpan.TotalMilliseconds > g_lidar1Config.btnsConfig[i].virtualKeyConfig.TriggerTimeout)
                        {
                            if (g_lidar1Config.btnsConfig[i].virtualKeyConfig.PressedDown == false)
                            {
                                // 发送模拟按键：方法1
                                //string keyStr = "{" + g_lidar1Config.btnsConfig[i].virtualKeyConfig.KeyImitate + "}";
                                //SendKeys.SendWait(keyStr);
                                // 发送模拟按键：方法2（http://t.zoukankan.com/LiangShanCamp-p-6393966.html）
                                keybd_event((Keys)Encoding.ASCII.GetBytes(g_lidar1Config.btnsConfig[i].virtualKeyConfig.KeyImitate)[0], 0, 0x0, 0); // 按键按下                                                                                                                   //keybd_event((Keys)Encoding.ASCII.GetBytes(g_lidar1Config.btnsConfig[i].virtualKeyConfig.KeyImitate)[0], 0, 0x2, 0); // 按键弹起

                                // 输出到UI
                                string msg = "Send key press down: " + g_lidar1Config.btnsConfig[i].virtualKeyConfig.KeyImitate;
                                object[] args = { msg };
                                this.Invoke(new DelegateUiUpdate(TxtLidar1DebugUpdate), args);
                            }

                            // 更新按键状态
                            g_lidar1Config.btnsConfig[i].virtualKeyConfig.PressedDown = true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Lidar1 cordinates data error, ex: " + ex.Message);
            }
        }

        /// <summary>
        /// 处理激光雷达2的数据
        /// </summary>
        /// <param name="data"></param>
        private void ProcessLidar2Data(string data)
        {
            data = data.Replace("\r", "").Replace("\n", "");
            string[] cordinates = data.Split(',');
            try
            {
                for (int i = 0; i < g_lidar2Config.btnsConfig.Length; i++)
                {
                    if (InRange(g_lidar2Config.btnsConfig[i].virtualKeyConfig.XCenter,
                    g_lidar2Config.btnsConfig[i].virtualKeyConfig.YCenter,
                    g_lidar2Config.btnsConfig[i].virtualKeyConfig.XRange,
                    g_lidar2Config.btnsConfig[i].virtualKeyConfig.YRange,
                    int.Parse(cordinates[0]),
                    int.Parse(cordinates[1])))
                    {
                        // 确认触发冷却
                        DateTime dTimeEnd = DateTime.Now;
                        TimeSpan timeSpan = dTimeEnd - g_lidar2Config.btnsConfig[i].virtualKeyConfig.LastTriggerTime;
                        g_lidar2Config.btnsConfig[i].virtualKeyConfig.LastTriggerTime = dTimeEnd; // 更新按键最后触发时间
                        //if (timeSpan != TimeSpan.Zero && timeSpan.TotalMilliseconds > g_lidar2Config.btnsConfig[i].virtualKeyConfig.TriggerTimeout)
                        {
                            if (g_lidar2Config.btnsConfig[i].virtualKeyConfig.PressedDown == false)
                            {
                                // 发送模拟按键：方法1
                                //string keyStr = "{" + g_lidar2Config.btnsConfig[i].virtualKeyConfig.KeyImitate + "}";
                                //SendKeys.SendWait(keyStr);
                                // 发送模拟按键：方法2（http://t.zoukankan.com/LiangShanCamp-p-6393966.html）
                                keybd_event((Keys)Encoding.ASCII.GetBytes(g_lidar2Config.btnsConfig[i].virtualKeyConfig.KeyImitate)[0], 0, 0x0, 0); // 按键按下                                                                                                                   //keybd_event((Keys)Encoding.ASCII.GetBytes(g_lidar2Config.btnsConfig[i].virtualKeyConfig.KeyImitate)[0], 0, 0x2, 0); // 按键弹起

                                // 输出到UI
                                string msg = "Send key press down: " + g_lidar2Config.btnsConfig[i].virtualKeyConfig.KeyImitate;
                                object[] args = { msg };
                                this.Invoke(new DelegateUiUpdate(TxtLidar2DebugUpdate), args);
                            }

                            // 更新按键状态
                            g_lidar2Config.btnsConfig[i].virtualKeyConfig.PressedDown = true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Lidar2 cordinates data error, ex: " + ex.Message);
            }
        }

        /// <summary>
        /// 检测坐标是否在指定区域范围内
        /// </summary>
        /// <param name="XCenter"></param>
        /// <param name="YCenter"></param>
        /// <param name="XOffset"></param>
        /// <param name="YOffset"></param>
        /// <param name="XCord"></param>
        /// <param name="YCord"></param>
        /// <returns></returns>
        private bool InRange(int XCenter, int YCenter, int XOffset, int YOffset, int XCord, int YCord)
        {
            if (XCord <= (XCenter + XOffset) && XCord >= (XCenter - XOffset) && YCord <= (YCenter + YOffset) && YCord >= (YCenter - YOffset))
            {
                return true;
            }
            else
                return false;
        }
        
        // 激光雷达1串口控制
        private void btnSerial1Ctrl_Click(object sender, EventArgs e)
        {
            try
            {
                if (btnSerial1Ctrl.Text == "打开串口" && !g_serialPort1.IsOpen)
                {
                    g_serialPort1.PortName = cboxSerial1PortNum.SelectedItem.ToString();
                    g_serialPort1.Open();
                    btnSerial1Ctrl.Text = "关闭串口";
                    this.pboxLidar1Status.Image = global::LidarCalibrateTool.Properties.Resources.toggle_on;
                    txtLidar1Debug.AppendText(g_serialPort1.PortName + "打开成功！\r\n");
                }
                else if (btnSerial1Ctrl.Text == "关闭串口" && g_serialPort1.IsOpen)
                {
                    g_serialPort1.Close();
                    btnSerial1Ctrl.Text = "打开串口";
                    this.pboxLidar1Status.Image = global::LidarCalibrateTool.Properties.Resources.toggle_off;
                    txtLidar1Debug.AppendText(g_serialPort1.PortName + "关闭成功！\r\n");
                }
            }
            catch (Exception ex)
            {
                txtLidar1Debug.AppendText("串口打开失败：" + ex.Message + "\r\n");
            }
        }

        // 串口可用性状态更新
        private void timerValidateSerialPort_Tick(object sender, EventArgs e)
        {
            string[] availablePorts = SerialPort.GetPortNames();

            if(availablePorts.Length <= 0)
                return;

            foreach (string port in cboxSerial1PortNum.Items)
            {
                if (!availablePorts.Contains(port))
                {
                    cboxSerial1PortNum.Items.Remove(port); // 删除失效的
                }
            }
            foreach (string port in cboxSerial2PortNum.Items)
            {
                if (!availablePorts.Contains(port))
                {
                    cboxSerial2PortNum.Items.Remove(port); // 删除失效的
                }
            }

            foreach (string port in availablePorts)
            {
                if (!cboxSerial1PortNum.Items.Contains(port))
                {
                    cboxSerial1PortNum.Items.Add(port); // 新增新发现的
                }

                if (!cboxSerial2PortNum.Items.Contains(port))
                {
                    cboxSerial2PortNum.Items.Add(port); // 新增新发现的
                }
            }

            if (cboxSerial1PortNum.SelectedItem == null && cboxSerial1PortNum.Items.Count > 0)
            {
                cboxSerial1PortNum.SelectedIndex = 0;
            }
            if (cboxSerial2PortNum.SelectedItem == null && cboxSerial2PortNum.Items.Count > 0)
            {
                cboxSerial2PortNum.SelectedIndex = 0;
            }
        }

        // 清除激光雷达1的调试区
        private void btnLidar1DebugClear_Click(object sender, EventArgs e)
        {
            txtLidar1Debug.Clear();
        }

        private void MainForm_SizeChanged(object sender, EventArgs e)
        {
            //当窗体最小化时
            if (WindowState == FormWindowState.Minimized)
            {
                //隐藏窗体
                Hide();
                //将托盘图标设为显示
                notifyIcon1.Visible = true;
            }
            else
            {
                //将托盘图标设为隐藏
                notifyIcon1.Visible = false;
                //显示窗体
                Show();
            }
        }

        // 双击恢复设置
        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            //显示窗体
            this.Show();
            //恢复窗体尺寸状态
            this.WindowState = FormWindowState.Normal;
        }

        // Lidar1的Treeview添加一个按键配置节点
        private void btnLidar1AddBtnConfig_Click(object sender, EventArgs e)
        {
            try
            {
                int i = 0;
                BtnConfig[] btnConfigs = new BtnConfig[g_lidar1Config.btnsConfig.Length + 1];

                foreach (BtnConfig config in g_lidar1Config.btnsConfig) // 遍历存储按键配置的对象数组
                {
                    btnConfigs[i] = config;

                    i++;
                }
                BtnConfig tmpBtnConfig = new BtnConfig();
                tmpBtnConfig.virtualKeyConfig = new VirtualKeyConfig();
                tmpBtnConfig.buttonName = txtLidar1ButtonName.Text;
                tmpBtnConfig.virtualKeyConfig.XCenter = int.Parse(txtLidar1BtnXCenter.Text);
                tmpBtnConfig.virtualKeyConfig.YCenter = int.Parse(txtLidar1BtnYCenter.Text);
                tmpBtnConfig.virtualKeyConfig.XRange = int.Parse(txtLidar1BtnXRange.Text);
                tmpBtnConfig.virtualKeyConfig.YRange = int.Parse(txtLidar1BtnYRange.Text);
                tmpBtnConfig.virtualKeyConfig.ReleaseTimeout = int.Parse(txtLidar1BtnReleaseTimout.Text);
                tmpBtnConfig.virtualKeyConfig.KeyImitate = cboxLidar1BtnImitateKey.Text;
                btnConfigs[i] = tmpBtnConfig;
                g_lidar1Config.btnsConfig = btnConfigs;

                // 存储对象序列化，并存储到JSON文件
                string jsonConfig = JsonConvert.SerializeObject(g_lidar1Config);
                File.WriteAllText("Lidar1_config.json", jsonConfig);

                // 输出调试信息到调试UI
                txtLidar1Debug.AppendText("增加节点并保存配置成功，存储到Lidar1_config.json文件！\r\n");

                // 重加载JSON
                LoadConfig(0);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        // Lidar1的Treeview删除一个按键配置节点
        private void btnLidar1DelBtnConfig_Click(object sender, EventArgs e)
        {
            try
            {
                int i = 0, j = 0;

                if (g_lidar1Config.btnsConfig.Length == 0)
                    return;
                BtnConfig[] btnConfigs = new BtnConfig[g_lidar1Config.btnsConfig.Length - 1];

                foreach (BtnConfig config in g_lidar1Config.btnsConfig) // 遍历存储按键配置的对象数组
                {
                    if (config.buttonName != tviewLidar1.SelectedNode.Text)
                    {
                        btnConfigs[j] = config;
                        j++;
                    }

                    i++;
                }
                g_lidar1Config.btnsConfig = btnConfigs;

                // 存储对象序列化，并存储到JSON文件
                string jsonConfig = JsonConvert.SerializeObject(g_lidar1Config);
                File.WriteAllText("Lidar1_config.json", jsonConfig);

                // 输出调试信息到调试UI
                txtLidar1Debug.AppendText("删除节点并保存配置成功，存储到Lidar1_config.json文件！\r\n");

                // 重加载JSON
                LoadConfig(0);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        // Lidar1的Treeview保存激光雷达1的虚拟按键配置
        private void btnSerialport1SaveConfig_Click(object sender, EventArgs e)
        {
            try
            {
                int i = 0;
                foreach (BtnConfig config in g_lidar1Config.btnsConfig) // 遍历存储按键配置的对象数组
                {
                    if (config.buttonName == tviewLidar1.SelectedNode.Text)
                    {
                        // 更新UI到该按键配置的存储对象
                        g_lidar1Config.btnsConfig[i].buttonName = txtLidar1ButtonName.Text;
                        g_lidar1Config.btnsConfig[i].virtualKeyConfig.XCenter = int.Parse(txtLidar1BtnXCenter.Text);
                        g_lidar1Config.btnsConfig[i].virtualKeyConfig.YCenter = int.Parse(txtLidar1BtnYCenter.Text);
                        g_lidar1Config.btnsConfig[i].virtualKeyConfig.XRange = int.Parse(txtLidar1BtnXRange.Text);
                        g_lidar1Config.btnsConfig[i].virtualKeyConfig.YRange = int.Parse(txtLidar1BtnYRange.Text);
                        g_lidar1Config.btnsConfig[i].virtualKeyConfig.ReleaseTimeout = int.Parse(txtLidar1BtnReleaseTimout.Text);
                        g_lidar1Config.btnsConfig[i].virtualKeyConfig.KeyImitate = cboxLidar1BtnImitateKey.Text;

                        // 存储对象序列化，并存储到JSON文件
                        string jsonConfig = JsonConvert.SerializeObject(g_lidar1Config);
                        File.WriteAllText("Lidar1_config.json", jsonConfig);

                        // 输出调试信息到调试UI
                        txtLidar1Debug.AppendText("保存配置成功，存储到Lidar1_config.json文件！\r\n");

                        // 重加载JSON
                        LoadConfig(0);

                        return;
                    }

                    i++;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        // Lidar2的TreeView节点切换事件
        private void tviewLidar2_AfterSelect(object sender, TreeViewEventArgs e)
        {
            //txtLidar1Debug.AppendText(e.Node.Text + " is selected!\r\n");
            foreach (BtnConfig config in g_lidar2Config.btnsConfig) // 遍历存储按键配置的对象数组
            {
                if (config.buttonName == e.Node.Text)
                {
                    // 更新该按键配置到UI
                    txtLidar2ButtonName.Text = config.buttonName;
                    txtLidar2BtnXCenter.Text = config.virtualKeyConfig.XCenter.ToString();
                    txtLidar2BtnYCenter.Text = config.virtualKeyConfig.YCenter.ToString();
                    txtLidar2BtnXRange.Text = config.virtualKeyConfig.XRange.ToString();
                    txtLidar2BtnYRange.Text = config.virtualKeyConfig.YRange.ToString();
                    txtLidar2BtnReleaseTimout.Text = config.virtualKeyConfig.ReleaseTimeout.ToString();
                    cboxLidar2BtnImitateKey.Text = config.virtualKeyConfig.KeyImitate;
                }
            }
        }

        // Lidar2的TreeView增加节点
        private void btnLidar2AddBtnConfig_Click(object sender, EventArgs e)
        {
            try
            {
                int i = 0;
                BtnConfig[] btnConfigs = new BtnConfig[g_lidar2Config.btnsConfig.Length + 1];

                foreach (BtnConfig config in g_lidar2Config.btnsConfig) // 遍历存储按键配置的对象数组
                {
                    btnConfigs[i] = config;

                    i++;
                }
                BtnConfig tmpBtnConfig = new BtnConfig();
                tmpBtnConfig.virtualKeyConfig = new VirtualKeyConfig();
                tmpBtnConfig.buttonName = txtLidar2ButtonName.Text;
                tmpBtnConfig.virtualKeyConfig.XCenter = int.Parse(txtLidar2BtnXCenter.Text);
                tmpBtnConfig.virtualKeyConfig.YCenter = int.Parse(txtLidar2BtnYCenter.Text);
                tmpBtnConfig.virtualKeyConfig.XRange = int.Parse(txtLidar2BtnXRange.Text);
                tmpBtnConfig.virtualKeyConfig.YRange = int.Parse(txtLidar2BtnYRange.Text);
                tmpBtnConfig.virtualKeyConfig.ReleaseTimeout = int.Parse(txtLidar2BtnReleaseTimout.Text);
                tmpBtnConfig.virtualKeyConfig.KeyImitate = cboxLidar2BtnImitateKey.Text;
                btnConfigs[i] = tmpBtnConfig;
                g_lidar2Config.btnsConfig = btnConfigs;

                // 存储对象序列化，并存储到JSON文件
                string jsonConfig = JsonConvert.SerializeObject(g_lidar2Config);
                File.WriteAllText("Lidar2_config.json", jsonConfig);

                // 输出调试信息到调试UI
                txtLidar2Debug.AppendText("增加节点并保存配置成功，存储到Lidar2_config.json文件！\r\n");

                // 重加载JSON
                LoadConfig(1);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        // Lidar2的TreeView删除节点
        private void btnLidar2DelBtnConfig_Click(object sender, EventArgs e)
        {
            try
            {
                int i = 0, j = 0;

                if (g_lidar2Config.btnsConfig.Length == 0)
                    return;
                BtnConfig[] btnConfigs = new BtnConfig[g_lidar2Config.btnsConfig.Length - 1];

                foreach (BtnConfig config in g_lidar2Config.btnsConfig) // 遍历存储按键配置的对象数组
                {
                    if (config.buttonName != tviewLidar2.SelectedNode.Text)
                    {
                        btnConfigs[j] = config;
                        j++;
                    }

                    i++;
                }
                g_lidar2Config.btnsConfig = btnConfigs;

                // 存储对象序列化，并存储到JSON文件
                string jsonConfig = JsonConvert.SerializeObject(g_lidar2Config);
                File.WriteAllText("Lidar2_config.json", jsonConfig);

                // 输出调试信息到调试UI
                txtLidar2Debug.AppendText("删除节点并保存配置成功，存储到Lidar2_config.json文件！\r\n");

                // 重加载JSON
                LoadConfig(1);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        // Lidar2的TreeView保存配置
        private void btnLidar2SaveConfig_Click(object sender, EventArgs e)
        {
            try
            {
                int i = 0;
                foreach (BtnConfig config in g_lidar2Config.btnsConfig) // 遍历存储按键配置的对象数组
                {
                    if (config.buttonName == tviewLidar2.SelectedNode.Text)
                    {
                        // 更新UI到该按键配置的存储对象
                        g_lidar2Config.btnsConfig[i].buttonName = txtLidar2ButtonName.Text;
                        g_lidar2Config.btnsConfig[i].virtualKeyConfig.XCenter = int.Parse(txtLidar2BtnXCenter.Text);
                        g_lidar2Config.btnsConfig[i].virtualKeyConfig.YCenter = int.Parse(txtLidar2BtnYCenter.Text);
                        g_lidar2Config.btnsConfig[i].virtualKeyConfig.XRange = int.Parse(txtLidar2BtnXRange.Text);
                        g_lidar2Config.btnsConfig[i].virtualKeyConfig.YRange = int.Parse(txtLidar2BtnYRange.Text);
                        g_lidar2Config.btnsConfig[i].virtualKeyConfig.ReleaseTimeout = int.Parse(txtLidar2BtnReleaseTimout.Text);
                        g_lidar2Config.btnsConfig[i].virtualKeyConfig.KeyImitate = cboxLidar2BtnImitateKey.Text;

                        // 存储对象序列化，并存储到JSON文件
                        string jsonConfig = JsonConvert.SerializeObject(g_lidar2Config);
                        File.WriteAllText("Lidar2_config.json", jsonConfig);

                        // 输出调试信息到调试UI
                        txtLidar2Debug.AppendText("保存配置成功，存储到Lidar2_config.json文件！\r\n");

                        // 重加载JSON
                        LoadConfig(1);

                        return;
                    }

                    i++;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        // Lidar2的TreeView节点切换事件
        private void btnLidar2DebugClear_Click(object sender, EventArgs e)
        {
            txtLidar2Debug.Clear();
        }

        // Lidar2串口控制
        private void btnSerial2Ctrl_Click(object sender, EventArgs e)
        {
            try
            {
                if (btnSerial2Ctrl.Text == "打开串口" && !g_serialPort2.IsOpen)
                {
                    g_serialPort2.PortName = cboxSerial2PortNum.SelectedItem.ToString();
                    g_serialPort2.Open();
                    btnSerial2Ctrl.Text = "关闭串口";
                    this.pboxLidar2Status.Image = global::LidarCalibrateTool.Properties.Resources.toggle_on;
                    txtLidar2Debug.AppendText(g_serialPort2.PortName + "打开成功！\r\n");
                }
                else if (btnSerial2Ctrl.Text == "关闭串口" && g_serialPort2.IsOpen)
                {
                    g_serialPort2.Close();
                    btnSerial2Ctrl.Text = "打开串口";
                    this.pboxLidar2Status.Image = global::LidarCalibrateTool.Properties.Resources.toggle_off;
                    txtLidar2Debug.AppendText(g_serialPort2.PortName + "关闭成功！\r\n");
                }
            }
            catch (Exception ex)
            {
                txtLidar2Debug.AppendText("串口打开失败：" + ex.Message + "\r\n");
            }
        }

        // 虚拟按键失效检测（失效则弹起按键）
        private void timerKeyRelease_Tick(object sender, EventArgs e)
        {
            for (int i = 0; i < g_lidar1Config.btnsConfig.Length; i++)
            {
                // 确认触发冷却
                DateTime dTimeEnd = DateTime.Now;
                TimeSpan timeSpan = dTimeEnd - g_lidar1Config.btnsConfig[i].virtualKeyConfig.LastTriggerTime;
                if (timeSpan != TimeSpan.Zero && timeSpan.TotalMilliseconds > g_lidar1Config.btnsConfig[i].virtualKeyConfig.ReleaseTimeout)
                {
                    if (g_lidar1Config.btnsConfig[i].virtualKeyConfig.PressedDown)
                    {
                        // 发送模拟按键：方法1
                        //string keyStr = "{" + g_lidar2Config.btnsConfig[i].virtualKeyConfig.KeyImitate + "}";
                        //SendKeys.SendWait(keyStr);
                        // 发送模拟按键：方法2（http://t.zoukankan.com/LiangShanCamp-p-6393966.html）
                        keybd_event((Keys)Encoding.ASCII.GetBytes(g_lidar1Config.btnsConfig[i].virtualKeyConfig.KeyImitate)[0], 0, 0x2, 0); // 按键弹起

                        // 更新按键状态
                        g_lidar1Config.btnsConfig[i].virtualKeyConfig.PressedDown = false;

                        // 输出到UI
                        string msg = "Send key release: " + g_lidar1Config.btnsConfig[i].virtualKeyConfig.KeyImitate;
                        object[] args = { msg };
                        this.Invoke(new DelegateUiUpdate(TxtLidar1DebugUpdate), args);
                    }
                }
            }

            for (int i = 0; i < g_lidar2Config.btnsConfig.Length; i++)
            {
                // 确认触发冷却
                DateTime dTimeEnd = DateTime.Now;
                TimeSpan timeSpan = dTimeEnd - g_lidar2Config.btnsConfig[i].virtualKeyConfig.LastTriggerTime;
                if (timeSpan != TimeSpan.Zero && timeSpan.TotalMilliseconds > g_lidar2Config.btnsConfig[i].virtualKeyConfig.ReleaseTimeout)
                {
                    if (g_lidar2Config.btnsConfig[i].virtualKeyConfig.PressedDown)
                    {
                        // 发送模拟按键：方法1
                        //string keyStr = "{" + g_lidar2Config.btnsConfig[i].virtualKeyConfig.KeyImitate + "}";
                        //SendKeys.SendWait(keyStr);
                        // 发送模拟按键：方法2（http://t.zoukankan.com/LiangShanCamp-p-6393966.html）
                        keybd_event((Keys)Encoding.ASCII.GetBytes(g_lidar2Config.btnsConfig[i].virtualKeyConfig.KeyImitate)[0], 0, 0x2, 0); // 按键弹起

                        // 更新按键状态
                        g_lidar2Config.btnsConfig[i].virtualKeyConfig.PressedDown = false;

                        // 输出到UI
                        string msg = "Send key release: " + g_lidar2Config.btnsConfig[i].virtualKeyConfig.KeyImitate;
                        object[] args = { msg };
                        this.Invoke(new DelegateUiUpdate(TxtLidar2DebugUpdate), args);
                    }
                }
            }
        }

        // Lidar1的TreeView节点切换事件
        private void tviewLidar1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            //txtLidar1Debug.AppendText(e.Node.Text + " is selected!\r\n");
            foreach (BtnConfig config in g_lidar1Config.btnsConfig) // 遍历存储按键配置的对象数组
            {
                if (config.buttonName == e.Node.Text)
                {
                    // 更新该按键配置到UI
                    txtLidar1ButtonName.Text = config.buttonName;
                    txtLidar1BtnXCenter.Text = config.virtualKeyConfig.XCenter.ToString();
                    txtLidar1BtnYCenter.Text = config.virtualKeyConfig.YCenter.ToString();
                    txtLidar1BtnXRange.Text = config.virtualKeyConfig.XRange.ToString();
                    txtLidar1BtnYRange.Text = config.virtualKeyConfig.YRange.ToString();
                    txtLidar1BtnReleaseTimout.Text = config.virtualKeyConfig.ReleaseTimeout.ToString();
                    cboxLidar1BtnImitateKey.Text = config.virtualKeyConfig.KeyImitate;
                }
            }
        }
    }
}
